#pragma once

#include <iostream>
#include <pthread.h>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

namespace wxd
{
    const size_t default_cap = 1;
    template <class T>
    class RingQueue
    {
    public:
        RingQueue(size_t cap = default_cap)
            : _sem_blank(cap), _sem_data(0), _p_index(0), _c_index(0), _capacity(cap)
        {
            _r_queue.reserve(cap);
        }
        // 生产者入队
        void Enqueue(T task)
        {
            // 申请空信号量 
            _sem_blank.P();
            { // 加锁
                LockGuard lock(&_pmutex);
                // //放入任务
                _r_queue[_p_index++] = task;
                _p_index %= _capacity; // 维持环形状态
            }
            _sem_data.V();
        }

        // 消费者出队
        void Pop(T *ptask)
        {
            // 申请data信号量
            _sem_data.P();
            {
                LockGuard lock(&_cmutex);
                // 拿走任务
                *ptask = _r_queue[_c_index++];
                _c_index %= _capacity;
            }
            _sem_blank.V();
        }

    private:
        std::vector<T> _r_queue; // 环形队列
        Sem _sem_blank;
        Sem _sem_data;
        size_t _p_index; // 生产者的坐标
        size_t _c_index;
        size_t _capacity;
        Mutex _cmutex;
        Mutex _pmutex;
    };
}